#include "TermDictBuilder.h"
bool TermDictBuilder::instanceFlag = false;

TermDictBuilder* TermDictBuilder::builderInstance = NULL;
TermDictBuilder* TermDictBuilder::getInstance()
{
    if(! instanceFlag){
    	builderInstance = new TermDictBuilder();
        return builderInstance;
    }
        return builderInstance;
}

size_t TermDictBuilder::addTermToMap(string key){
	size_t returnId = termId;
	pair<MAPTYPE::iterator, bool> it;
	it = termMap.insert(make_pair(key, valueType(termId, 1)));
	if( !it.second ){ //term exist
		it.first->second.count++;
		returnId = it.first->second.id;
	}
	termId++;
	return returnId;
}
void TermDictBuilder::addRawDataToMap(string key){
	pair<MAPTYPE::iterator, bool> it;
	it = rawDataMap.insert(make_pair(key, valueType(rawDataId, 1)));
	if( !it.second ){ //term exist
		it.first->second.count++;
	}
}

void TermDictBuilder::printMap(){
	MAPTYPE::iterator iter1;
	for(iter1 = termMap.begin(); iter1 != termMap.end(); iter1++){
		cout << iter1->first << ":" << iter1->second.id << "," << iter1->second.count << endl;
	}
	MAPTYPE::iterator iter2;
	for(iter2 = rawDataMap.begin(); iter2 != rawDataMap.end(); iter2++){
		cout << iter1->first << ":" << iter1->second.id << "," << iter1->second.count << endl;
	}
}

void TermDictBuilder::writeTermTofile(){
	ofstream termDictstream;
	ofstream termCountstream;
	config* configInstance = config::getInstance();
	string dirPath = configInstance->getValue("path_to_dict_store_dir");
	termDictstream.open((dirPath+"/term_dict.txt").c_str(), ios::out);
	termCountstream.open((dirPath+"/term_count_dict.txt").c_str(), ios::out);

	MAPTYPE::iterator iter;
	for(iter = termMap.begin(); iter != termMap.end(); iter++){
		termDictstream << iter->second.id << " " << iter->first << endl;
		termCountstream << iter->second.id << " " << iter->second.count << endl;
	}
	termDictstream.close();
	termCountstream.close();
}

void TermDictBuilder::writeRawDataToFile(){
	FILE* fp = fopen("Dict/raw_data_temp.txt", "r");
	if( fp ){
		megerRawDataToFile();
	}else{
		createRawDataTempFile();
	}
}

void TermDictBuilder::createRawDataTempFile(){
	ofstream rawDataTempStream;
	config* configInstance = config::getInstance();
	string dirPath = configInstance->getValue("path_to_dict_store_dir");
	rawDataTempStream.open((dirPath+"/raw_data.txt").c_str(), ios::out);

	MAPTYPE::iterator iter;
	for(iter = rawDataMap.begin(); iter != rawDataMap.end(); iter++){
		rawDataTempStream << iter->first << " " << iter->second.id << " " << iter->second.count << endl;
	}
	rawDataTempStream.close();
	rawDataMap.clear();
}

void TermDictBuilder::megerRawDataToFile(){
	ifstream readFile;
	ofstream writeFile;

	config* configInstance = config::getInstance();
	string dirPath = configInstance->getValue("path_to_dict_store_dir");
	readFile.open((dirPath+"/raw_data_temp.txt").c_str(), ios::in);
	writeFile.open((dirPath+"/new_raw_data_temp.txt").c_str(), ios::out);

	if(readFile.is_open() && writeFile.is_open()){
		MAPTYPE::iterator iter = rawDataMap.begin();
		string line;
		//getline(readFile, line);
		while( (!readFile.eof()) && iter!= rawDataMap.end() ){
			getline(readFile, line);
			vector<string> v;
			CUtilities::tokenize(line, v, " ");
			if( v.size() < 3 ) break;
			//determine the current term from file exsit in map
			MAPTYPE::iterator iterFinder = rawDataMap.find(v.at(0));
			//exsit in both of file and memory
			if( iterFinder != rawDataMap.end() ) {//need merge
				MAPTYPE::iterator it = iter;
				for( it; it->first != iterFinder->first; it++ ){
					writeFile << it->first << " " << it->second.id << " " << it->second.count<< endl;
					iter++;
				}
				//merge them together
				int fileCount;
				CUtilities::string_to_number(fileCount, v.at(2));
				writeFile << iter->first << " " << iter->second.id << " " << (fileCount + iter->second.count)<< endl;
				//getline(readFile, line);
				iter++;
			}else{ //don't need merge
				if( v.at(0) < iter->first ){
					writeFile << line << endl;
					//getline(readFile, line);
				} else if( v.at(0) > iter->first ){
					writeFile << iter->first << " " << iter->second.id << "" << iter->second.count << endl;
					iter++;
				}
			}
		}
		//write the rest of memory or map into temp file
		if( !readFile.eof() ){
			while( getline(readFile, line) ){
				writeFile << line << endl;
			}
		}else if( iter != rawDataMap.end() ){
			for( iter; iter !=rawDataMap.end(); iter++ ){
				writeFile << iter->first << " " << iter->second.id << "" << iter->second.count << endl;
			}
		}
	}

	readFile.close();
	writeFile.close();


	remove((dirPath+"/raw_data_temp.txt").c_str());
	rename((dirPath+"/new_raw_data_temp.txt").c_str(), (dirPath+"/raw_data_temp.txt").c_str());

	rawDataMap.clear();
}
void TermDictBuilder::generateFinalRawDataFile(){
	ifstream rawDataTempStream;
	ofstream rawDataDictStream;
	ofstream rawDataCountStream;

	config* configInstance = config::getInstance();
	string dirPath = configInstance->getValue("path_to_dict_store_dir");

	rawDataTempStream.open((dirPath+"/raw_data_temp.txt").c_str(), ios::in);
	rawDataDictStream.open((dirPath+"/raw_data_term.txt").c_str(), ios::out);
	rawDataCountStream.open((dirPath+"/raw_data_count.txt").c_str(), ios::out);

	if(rawDataTempStream.is_open() && rawDataDictStream.is_open() && rawDataCountStream.is_open()){
		string line;
		while(!rawDataTempStream.eof()){
			getline(rawDataTempStream, line);
			vector<string> v;
			CUtilities::tokenize(line, v, " ");
			if( v.size() == 3 ){
				rawDataDictStream << v.at(0) << " " << v.at(1) << endl;
				rawDataCountStream << v.at(1) << " " << v.at(2) << endl;
			}
		}
	}

	rawDataTempStream.close();
	rawDataDictStream.close();
	rawDataCountStream.close();

	remove((dirPath+"/raw_data_temp.txt").c_str());
}

size_t TermDictBuilder::addTermToMapNoCount(string key) {
	size_t returnId = termId;
	pair<MAPTYPE::iterator, bool> it;
	it = termMap.insert(make_pair(key, valueType(termId, 0)));
	if( !it.second ){ //term exist
		returnId = it.first->second.id;
	}
	termId++;
	return returnId;
}

bool TermDictBuilder::isRawDataMapFull(){
	if( rawDataMap.size() >= 5000 ){
		return true;
	}else{
		return false;
	}
}
